﻿#pragma once
#include "..\..\include\Server\CAsyncServer.h"
#include "..\..\include\common\CEasyDialog.h"
#include "..\..\include\Server\CMyServer.h"

CEasyDialog wndServer;	//窗口对象

//服务端程序功能实现对象
CMyServer ui;

//服务端消息处理函数
BOOL CALLBACK ServerProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{		
	//绑定窗口句柄
	ui.SetWindowHandle(wndServer.GetHandle());

	//CDebug debug;
	//////////////////////////////////////////////////////////////////////////
	switch(uMsg)
	{
	case WM_INITDIALOG:
		//初始化公共控件
		if (ui.InitCom() == FALSE)
		{
			::MessageBox(wndServer.GetHandle(), _T("初始化程序错误"), _T("错误"), MB_ICONSTOP);
			::PostQuitMessage(EXIT_FAILURE);
		}

		return TRUE;

	case WM_SHOWWINDOW:
		ui.InitUI();
		return TRUE;

	case WM_CLOSE:
		//询问是否退出服务端
		if (MessageBox(wndServer.GetHandle(), _T("是否要退出服务端？"), _T("提示"), MB_ICONQUESTION | MB_YESNO) == IDYES)
		{
			::PostQuitMessage(EXIT_SUCCESS);
		}
		return TRUE;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDC_START_BUTTON:
			//开启服务
			ui.StartServer();
			break;

			return TRUE;
		case IDC_STOP_BUTTON:
			//关闭服务
			ui.StopServer();

			break;
		}
		return TRUE;

	case WM_NOTIFY:
		switch (((LPNMHDR)lParam)->code)
		{
		case NM_CLICK:
			//清除日志
			if (((LPNMHDR)lParam)->idFrom == IDC_CLEARLOG_LINK)
			{
				ui.ClearLog();
			}
			break;
		}

		return TRUE;

	case WM_SOCKET:
		SOCKET s = wParam;

		//检测套接字是否发生错误
		if (WSAGETSELECTERROR(lParam))
		{

			//获取套接字信息
			sockaddr_in addr;
			int nAddrLen = sizeof(addr);
			::getpeername(s, (sockaddr*)&addr, &nAddrLen);

			ui.AddLog("客户端连接 [%s:%d] 发生错误.", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
			
			//查询发生错误的客户端
			//CLIENT_INFO Client_Error;
			//ui.server.QueryClient(s, &Client_Error);

			//从客户端队列中删除
			::closesocket(s);
			ui.server.DelClient(s);

			//ui.UpdateOnlineList();

			return TRUE;
		}

		//处理套接字事件
		if (WSAGETSELECTEVENT(lParam) == FD_ACCEPT)
		{
			sockaddr_in addr;
			int nAddrLen = sizeof(addr);
			SOCKET sckNewClient = ::accept(s, (sockaddr*)&addr, &nAddrLen);
			ui.AddLog("客户端 [%s:%d] 已连接.", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

			//投递其它通知
			::WSAAsyncSelect(sckNewClient, hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
		}
		else if (WSAGETSELECTEVENT(lParam) == FD_WRITE)
		{
			
		}
		else if (WSAGETSELECTEVENT(lParam) == FD_READ)
		{

			//sockaddr_in addr;
			//int nAddrLen = sizeof(addr);
			//::getpeername(s, (sockaddr*)&addr, &nAddrLen);
			//ui.AddLog("接收到来自[%s:%d]数据...", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
			NET_CMD cmd;
			::recv(s, (char*)&cmd, sizeof(cmd), 0);
			ui.DispatchCommand(s, cmd);
		}
		else if (WSAGETSELECTEVENT(lParam) == FD_CLOSE)
		{
			//获取套接字信息
			sockaddr_in addr;
			int nAddrLen = sizeof(addr);
			::getpeername(s, (sockaddr*)&addr, &nAddrLen);

			ui.AddLog("客户端连接 [%s:%d] 已经退出.", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
			::closesocket(s);
		}

		return TRUE;
	}//switch(uMsg)

	return FALSE;
};

//心跳包时间检测函数
VOID CALLBACK Heart_CheckProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
	if (ui.server.m_ClientList.empty() == true)
	{
		//更新列表
		ui.UpdateOnlineList();
		return;
	}

	CDebug debug;
	debug.Trace("正在检测心跳包超时...\n");

	//查找函数
	bool findIF(CLIENT_INFO &s);

	/*遍历客户端队列，如果心跳包时间间隔为0则踢出队列*/
	list<CLIENT_INFO>::iterator iter = find_if(ui.server.m_ClientList.begin(), ui.server.m_ClientList.end(), findIF);
	if (iter != ui.server.m_ClientList.end())
	{
		::closesocket(iter->s);
		ui.AddLog("用户[%s]心跳包同步超时，已踢下线。", iter->username);
		ui.server.m_ClientList.erase(iter);
	}
}

bool findIF(CLIENT_INFO &s)
{
	return s.nHeartPacketTime <= 0;
}

//心跳包时间倒计时函数
VOID CALLBACK Heart_DealTimeProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
	if (ui.server.m_ClientList.empty() == true)
	{
		//更新列表
		ui.UpdateOnlineList();
		return;
	}

	/*遍历客户端队列，把所有客户端的倒计时时间减去1秒*/
	for (list<CLIENT_INFO>::iterator iter = ui.server.m_ClientList.begin(); 
		iter != ui.server.m_ClientList.end(); iter++)
	{
		if (iter->nHeartPacketTime > 0)
		{
			iter->nHeartPacketTime --;
		}
	}

	//更新列表
	ui.UpdateOnlineList();
}